home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Gold Collection / Software Vault - The Gold Collection (American Databankers) (1993).ISO / cdr49 / 123_01.zip / PP.C < prev    next >
Text File  |  1993-06-07  |  14KB  |  642 lines

  1.  /*******************************************************\
  2. **    A preprocessor using the "C" syntax        **
  3. **    described by K&R in "The C Programming        **
  4. **    Language."  Based on the macro processor    **
  5. **    in Ratfor from K&P's "Software Tools."        **
  6. **                            **
  7. **    Robert T Pasky                    **
  8. **    36 Wiswall Rd                    **
  9. **    Newton Centre, MA 02159                **
  10. **    (617) 964-3641                    **
  11.  \*******************************************************/
  12.  
  13. /*
  14. **    format is:
  15. **        pp <infile> [<outfile>] [-d]\n");
  16. **
  17. **    if <outfile> is not given, output will be placed in
  18. **    <infile>.PP.
  19. **    The optional -d turns on the debug mode which is only
  20. **    useful if you want to watch what goes on inside the
  21. **    program as it crunches files.
  22. **
  23. **    This version is not simply a translation from the
  24. **    Ratfor version: it was modified to conform to the
  25. **    "official" format of the C preprocessor as defined
  26. **    in the K&R C Programming Language book.
  27. **    The output file can be fed into the BDS C compiler;
  28. **    or any other compiler (and other languages?) for
  29. **    which the input was intended.
  30. **
  31. **    This program has #include file capability and
  32. **    symbolic parameter substitution. That means you
  33. **    can write something like:
  34. **        #define max(a,b) (a) > (b) ? (a) : (b)
  35. **    which will replace:
  36. **        max(x+1,y-1)
  37. **    with:
  38. **        (x+1) > (y-1) ? (x+1) : (y-1)
  39. **
  40. **    Here "max(a,b)" is a template with two parameters:
  41. **    a and b. When the preprocessor sees "max(x+1,y-1)"
  42. **    it replaces the first parameter (a) in the definition
  43. **    with "x+1" and the second parameter ("b") with "y-1".
  44. **    Notice that the "(" must follow "max" with no intervening
  45. **    spaces. That's so the preprocessor can differentiate
  46. **    between argumented and non-argumented macros, e.g.,
  47. **    "#define ERROR (-1)".
  48. **    Secondly, the a and b in the definition are surrounded
  49. **    by parentheses. This is often a good idea; it avoids
  50. **    problems that might occur with precedence rules, e.g.:
  51. **    #define div(a,b) a/b
  52. **    ... div(x+2,5)
  53. **    would result in "x+2/5" which is interpreted as x+(2/5)
  54. **    instead of the intended "(x+2)/5".
  55. **
  56. **    Note: this program has NOT been rigorously tested
  57. **    and, as provided here, is quite limited in its array
  58. **    size (it's easy enough to increase the defines for
  59. **    the array sizes if you have lots of memory).
  60. **    The proportions allocated among the various arrays
  61. **    may also need tuning. For example, if you like to use
  62. **    lots of short define strings you might increase MAXTOK
  63. **    and MAXDEF. On the other hand, if you have relatively
  64. **    few defines but they tend to be long-winded, you could
  65. **    shorten these in favor of increasing MAXTBL (and
  66. **    possibly DEFSIZ).
  67. */
  68.  
  69. #include "bdscio.h"
  70.  
  71. #define STDOUT 1
  72.  
  73. #define STDERR 1    /* EKR 3/10/83 */
  74. #define YES 1        /* EKR 3/10/83 */
  75. #define NO 0        /* EKR 3/10/83 */
  76. #define NUL NULL    /* EKR 3/10/83 */
  77. #define EQUAL 0        /* EKR 3/10/83 */
  78.  
  79. #define ALPHA 'a'
  80. #define LETTER 'a'
  81. #define DIGIT '9'
  82. #define LPAREN '('
  83. #define RPAREN ')'
  84. #define LBRACK '('
  85. #define RBRACK ')'
  86. #define COMMA ','
  87. #define ARGFLAG 0xFA
  88. #define HASH '#'
  89. #define DEFTYPE 0xFC
  90. #define INCTYPE 0xFB
  91. #define MAXFILNAME 20
  92. #define CHARBUFSIZE 80
  93. #define MAXDEF 600
  94. #define MAXTOK 200
  95. #define MAXTBL 1000
  96. #define MAXPTR 600
  97. #define DEFSIZ 129
  98. #define TOKSIZ 129
  99. #define EVALSIZE 200
  100. #define ARGSIZE 200
  101. #define CALLSIZE 200
  102.  
  103. int bp;
  104. char buf[CHARBUFSIZE];
  105. char inbuf[BUFSIZ], incbuf[BUFSIZ], outbuf[BUFSIZ];
  106. char outfile[MAXFILNAME], incfil[MAXFILNAME];
  107. char defn[MAXDEF], token[MAXTOK], table[MAXTBL];
  108. int namptr[MAXPTR];
  109. int lastp, lastt;
  110. int cp, ep;
  111. char evalst[EVALSIZE];
  112. int ap, argstk[ARGSIZE], callst[CALLSIZE];
  113. int nlb, plev[CALLSIZE];
  114. int incflg;
  115.  
  116. int debug;
  117.  
  118. main(argc, argv)
  119. int argc;
  120. char **argv;
  121. {
  122. /*
  123. **    macro - expand macros with arguments
  124. */
  125.     char t, *defnam, *incnam, *s;
  126.     int deftyp[2];
  127.     char *balp;
  128.  
  129.     debug = FALSE;
  130.     deftyp[0] = DEFTYPE;
  131.     deftyp[1] = NUL;
  132.     defnam = "#define";
  133.     incnam = "#include";
  134.     incflg = NO;
  135.     balp = "()";
  136.     bp = -1;
  137.     lastp = lastt = -1;
  138.  
  139.     printf("pp v1.0\n");
  140.  
  141.     if (argc < 2)
  142.         perr("usage: pp <infile> [<outfile>] [-d]\n");
  143.     s = *++argv;
  144.     if (fopen(s, inbuf) == ERROR)
  145.         perr1("cannot open <%s>", s);
  146.     argc -= 2; argv++;
  147.     if (argc > 0 && **argv != '-') {
  148.         strcpy (outfile, s = *argv++);
  149.         argc--;
  150.         }
  151.     else    {
  152.         strcpy (outfile, s);
  153.         strcat (outfile, ".PP");
  154.         }
  155.     if (fcreat(outfile, outbuf) == ERROR)
  156.         perr1("cannot create <%s>", outfile);
  157.     fprintf(STDERR, "output will be in <%s>\n", outfile);
  158.  
  159.     while (argc-- > 0) {
  160.         s = *argv++;
  161.         if (strcmp(s, "-D") == EQUAL)
  162.             debug = TRUE;
  163.         }
  164.     if (debug) fprintf(STDERR,"debug is on\n");
  165.  
  166.     instal(defnam, deftyp);
  167.     deftyp[0] = INCTYPE;
  168.     instal(incnam, deftyp);
  169.     cp = -1;
  170.     ap = ep = 0;
  171.     for (t = gettok(); t != CPMEOF; t = gettok()) {
  172.         if (t == ALPHA) {
  173.             if (lookup(token, defn) == NO)
  174.                 puttok(token);
  175.             else {
  176.                 if (*defn == INCTYPE) {
  177.                     doinc();
  178.                     continue;
  179.                     }
  180.                 if (++cp > CALLSIZE)
  181.                     perr("call stack overflow\n");
  182.                 callst[cp] = ap;
  183.                 ap = push(ep, argstk, ap);
  184.                 puttok(defn);
  185.                 putchr(NUL);
  186. if (debug) fprintf(STDERR, "push defn: <%s>\n", defn);
  187.                 ap = push(ep, argstk, ap);
  188. /*********************/
  189.                 if (*defn == DEFTYPE)
  190.                     while (isspace(gettok()))
  191.                         ;
  192. /*********************/
  193.                 puttok(token);
  194.                 putchr(NUL);
  195. if (debug) fprintf(STDERR, "push name: <%s>\n", token);
  196.                 ap = push(ep, argstk, ap);
  197.                 t = gettok();
  198.                 pbstr(token);
  199. if (debug) fprintf(STDERR, "next token: <%s>\n", token);
  200.                 if (t != LPAREN)
  201.                     pbstr(balp);    /* add () if none */
  202.                 plev[cp] = 0;
  203.                 }
  204.             }
  205.         else if (cp == -1)
  206.             puttok(token);
  207. /*        else if (t == LBRACK) {
  208. **            nlb = 1;
  209. **            while (1) {
  210. **                t = gettok();
  211. **                if (t == LBRACK)
  212. **                    nlb++;
  213. **                else if (t == RBRACK) {
  214. **                    nlb--;
  215. **                    if (nlb == 0)
  216. **                        break;
  217. **                    }
  218. **                else if (t == CPMEOF)
  219. **                    perr("EOF in string\n");
  220. **                puttok(token);
  221. **                }
  222. **            }
  223. */
  224.         else if (t == LPAREN) {
  225.             if (plev[cp]++ > 0)
  226.                 puttok(token);
  227.             }
  228.         else if (t == RPAREN) {
  229.             if (--plev[cp] > 0)
  230.                 puttok(token);
  231.             else {
  232.                 putchr(NUL);
  233.                 eval(argstk, callst[cp], ap - 1);
  234.                 ap = callst[cp];    /* pop eval stack */
  235.                 ep = argstk[ap];
  236.                 cp--;
  237.                 }
  238.             }
  239.         else if (t == COMMA && plev[cp] == 1) {
  240.             putchr(NUL);
  241.             ap = push(ep, argstk, ap);
  242.             }
  243.         else
  244.             puttok(token);
  245.         }
  246.     if (cp != -1)
  247.         perr("unexpected EOF (not at level 0)\n");
  248.  
  249.     putc(CPMEOF, outbuf);
  250.     fflush(outbuf);
  251.     fclose(outbuf);
  252.     exit();
  253. }
  254.  
  255. perr(s)
  256. char *s;
  257. {
  258.     fprintf(STDERR, s);
  259.     exit();
  260. }
  261.  
  262. perr1(s, t)
  263. char *s, *t;
  264. {
  265.     fprintf(STDERR, s, t);
  266.     exit();
  267. }
  268. /*
  269. **    lookup - locate name, extract def. from table
  270. */
  271. lookup(name, defn)
  272. char name[], defn[];
  273. {
  274.     int i, j, k;
  275.  
  276. if(debug) fprintf(STDERR, "lookup: name <%s>...", name);
  277.  
  278.     for (i = lastp; i >= 0; i--) {
  279.  
  280. if(debug) fprintf(STDERR, "\nnamptr: %d table: <%s>",
  281.      namptr[i], &table[namptr[i]]);
  282.  
  283.         if (strcmp(&table[namptr[i]], name) == EQUAL) {
  284.             j = strlen(name) + 1;
  285.             strcpy (defn, &table[namptr[i] + j]);
  286.  
  287. if(debug) fprintf(STDERR, "found! defn: <%s>\n", defn);
  288.  
  289.             return(YES);
  290.             }
  291.         }
  292. if(debug) fprintf(STDERR, "not found.\n");
  293.  
  294.     return(NO);
  295. }
  296.  
  297. /*
  298. **    instal - add name and definition to table
  299. */
  300. instal(name, defn)
  301. char name[], defn[];
  302. {
  303.     int dlen, nlen;
  304.  
  305. if(debug) fprintf(STDERR, "instal: name <%s> defn <%s>\n", name, defn);
  306.  
  307.     nlen = strlen(name) + 1;
  308.     dlen = strlen(defn) + 1;
  309.     if (lastt + nlen + dlen > MAXTBL || lastp >= MAXPTR)
  310.         fprintf(STDERR, "<%s>: too many defns\n", name);
  311.  
  312.     namptr[++lastp] = lastt + 1;
  313.     strcpy(&table[lastt + 1], name);
  314.     strcpy(&table[lastt + nlen + 1], defn);
  315.     lastt += nlen + dlen;
  316. }
  317.  
  318. /*
  319. **    getdef - for no arguments - get name and definition
  320. */
  321. getdef(token, defn)
  322. char token[], defn[];
  323. {
  324.     int i, nlpar;
  325.     char c;
  326.  
  327. if(debug) fprintf(STDERR, "getdef: token <%s>\n", token);
  328.  
  329.     if ((c = ngetc()) != LPAREN)
  330.         perr("missing left paren\n");
  331.     else if (gettok() != ALPHA)
  332.         perr("non-alphanumeric token\n");
  333.     else if ((c = ngetc()) != COMMA)
  334.         perr("missing comma in define\n");
  335.     /* else got name */
  336.     nlpar = 0;
  337.     for (i = 0; nlpar >= 0; i++)
  338.         if (i >= DEFSIZ)
  339.             perr("definition too long\n");
  340.         else if ((defn[i] = ngetc()) == CPMEOF)
  341.             perr("missing right paren\n");
  342.         else if (defn[i] == LPAREN)
  343.             nlpar++;
  344.         else if (defn[i] == RPAREN)
  345.             nlpar--;
  346.         /* else normal char in defn[i] */
  347.     defn[i - 1] = NUL;
  348. }
  349. /*
  350. **    Get alphanumeric string or single non-alpha for define
  351. */
  352. gettok()
  353. {
  354.     char tok, ntok;
  355.     int i, clev;
  356.  
  357. if(debug) fprintf(STDERR, "gettok: ");
  358.     for (i = 0; i < TOKSIZ; i++) {
  359.         tok = type(token[i] = ngetc());
  360.         if (tok != LETTER && tok != DIGIT && tok != HASH)
  361.             break;
  362.         }
  363.     if (i == 0) {
  364.         if (tok == '"' || tok == '\'') {
  365.  
  366. if (debug) fprintf(STDERR, "gettok: in quote\n");
  367.  
  368.             for (i++; i < TOKSIZ; i++) {
  369.                 if ((token[i] = ngetc()) != '\\') {
  370.                     if (token[i] == tok)
  371.                         break;
  372.                     }
  373.                 else
  374.                     token[++i] = ngetc();
  375.                 }
  376.             if (i >= TOKSIZ)
  377.                 perr("token too long\n");
  378.             token[i+1] = NUL;
  379.             return(tok);
  380.             }
  381.         else if (tok == '/') if ((ntok = ngetc()) == '*') {
  382.             clev = 1;
  383.             i = 0;
  384.             tok = token[i] = ' ';
  385. if (debug) fprintf(STDERR, " in comment\n");
  386.  
  387. comnt:            while (tok != '*' && tok != '/' && tok != CPMEOF)
  388.                 tok = ngetc();
  389.             if (tok == CPMEOF)
  390.                 perr("EOF in comment\n");
  391.             ntok = ngetc();
  392.             if (tok == '/' && ntok == '*')
  393.                 clev++;
  394.             if (tok == '*' && ntok == '/')
  395.                 clev--;
  396.             if (clev > 0) {
  397.                 tok = ntok;
  398.                 goto comnt;
  399.                 }
  400.             }
  401.         else if (tok == '/' && ntok != '*')
  402.             putbak(ntok);
  403.         }
  404.     if (i >= TOKSIZ)
  405.         perr("token too long\n");
  406.     if (i > 0) {
  407.         putbak(token[i--]);
  408.         tok = ALPHA;
  409.         }
  410.     token[i+1] = NUL;
  411. if(debug) fprintf(STDERR, " token: <%s> type: %c\n", token, tok);
  412.     return(tok);
  413.  
  414. }
  415.  
  416. puttok(str)
  417. char str[];
  418. {
  419.     int i;
  420.  
  421. if (debug) fprintf(STDERR, "puttok: <%s> cp:%d ep:%d ap:%d\n",
  422.     str, cp, ep, ap);
  423.  
  424.     for (i = 0; str[i] != NUL; i++)
  425.         putchr(str[i]);
  426. }
  427.  
  428. putchr(c)
  429. char c;
  430. {
  431.     if (cp == -1) {
  432.         if (c == '\n')
  433.             putc('\r', outbuf);
  434.         putc(c, outbuf);
  435.         }
  436.     else {
  437.         if (ep > EVALSIZE)
  438.             perr("evaluation stack overflow\n");
  439.         evalst[ep++] = c;
  440.         }
  441. }
  442.  
  443. push(ep, argstk, ap)
  444. int ep, argstk[], ap;
  445. {
  446. if (debug) fprintf(STDERR, "push: ep: %d ap: %d\n", ep, ap);
  447.  
  448.     if (ap > ARGSIZE)
  449.         perr("arg stack overflow\n");
  450.     argstk[ap] = ep;
  451.     return (ap + 1);
  452. }
  453.  
  454. eval(argstk, i, j)
  455. int argstk[], i, j;
  456. {
  457.     int k, m, n, t, td, argno;
  458.  
  459.     t = argstk[i];
  460.     td = evalst[t];
  461.  
  462. if (debug) fprintf(STDERR, "eval: t: %d td: <%s>\n", t, &evalst[t]);
  463.  
  464.     if (td == DEFTYPE)
  465.         dodef(argstk, i, j);
  466.     else {
  467.         for (k = t + strlen(&evalst[t]) - 1; k > t; k--) {
  468.  
  469. if (debug) fprintf(STDERR, "eval: k: %d evalst: <%c%c>\n",
  470.     k, evalst[k-1], evalst[k]);
  471.  
  472.             if (evalst[k-1] != ARGFLAG)
  473.                 putbak(evalst[k]);
  474.             else {
  475.                 if (isdigit(evalst[k]))
  476.                     argno = evalst[k] - '0';
  477.                 else    argno = -1;
  478.                 if (argno >= 0 && argno < (j - i)) {
  479.                     n = i + argno + 1;
  480.                     m = argstk[n];
  481.                     pbstr(&evalst[m]);
  482.  
  483. if (debug) fprintf(STDERR, "eval: n%d: m%d: <%s>", n, m, &evalst[m]);
  484.  
  485.                     }
  486.                 k--; /* skip over $ */
  487.                 }
  488.             }
  489.         if (k == t) {
  490.             putbak(evalst[k]);
  491.  
  492. if (debug) fprintf(STDERR, "eval: k==t: <%s>", &evalst[k]);
  493.  
  494.             }
  495.         }
  496.  
  497. }
  498.  
  499. dodef(argstk, i, j)
  500. int argstk[], i, j;
  501. {
  502.     int a1, a2, k;
  503.     char t;
  504.  
  505. if (debug) fprintf(STDERR, "dodef: i:%d j:%d\n", i, j);
  506.  
  507.     if (j - i > 1) {
  508.         a1 = argstk[i+1];
  509.         do
  510.             t = gettok();
  511.         while (isspace(*token));
  512.         ap = push(ep, argstk, ap);
  513. /*        if (++cp > CALLSIZE)
  514. **            perr("call stack overflow\n");
  515. */
  516.         while (*token != '\n') {
  517.             for (k = i + 2; k <= j; k++) {
  518.                 a2 = argstk[k];
  519.  
  520. if (debug) fprintf(STDERR, "strcmp: <%s> %d:<%s>\n",
  521.     token, k, &evalst[a2]);
  522.  
  523.                 if (strcmp(&evalst[a2], token) == EQUAL)
  524.                     break;
  525.                 }
  526.             if (k <= j) {
  527.                 putchr(ARGFLAG);
  528.                 putchr('0' + k - i - 1);
  529.                 }
  530.             else
  531.                 puttok(token);
  532.             t = gettok();
  533.             }
  534.         while (isspace(evalst[ep - 1]))
  535.             ep--;
  536.         putchr(NUL);
  537.         a2 = argstk[ap - 1];
  538.  
  539. if (debug) fprintf(STDERR, "dodef: name: <%s> defn: <%s>\n",
  540.     &evalst[a1], &evalst[a2]);
  541.  
  542.         instal(&evalst[a1], &evalst[a2]); /* subarrays */
  543. /*        cp--;
  544. */
  545.         }
  546. }
  547.  
  548. doinc()
  549. {
  550.     char c, d;
  551.     int i;
  552.  
  553.     if (incflg == YES)
  554.         perr("can't nest includes\n");
  555.     while(isspace(c = ngetc()))
  556.         ;
  557.     if (c == CPMEOF)
  558.         perr("unexpected EOF (#include)\n");
  559.     if (c == '<')        d = '>';
  560.     else if (c == '"')    d = '"';
  561.     else
  562.         perr("bad include argument\n");
  563.     for (i = 0; c != CPMEOF && c != '\n'; i++) {
  564.         if ((c = ngetc()) == d)
  565.             break;
  566.         incfil[i] = c;
  567.         if (i > MAXFILNAME)
  568.             perr("filename too long\n");
  569.         }
  570.     if (i > 0)
  571.         incfil[i] = NUL;
  572.     else
  573.         perr("illegal include name\n");
  574.     if (fopen(incfil, incbuf) == ERROR)
  575.         perr1("can't include <%s>\n", incfil);
  576.     while (c != '\n' && c != CPMEOF)
  577.         c = ngetc();
  578.     incflg = YES;
  579. }
  580.  
  581.  
  582. type(c)
  583. char c;
  584. {
  585.     if (isalpha(c)) return(LETTER);
  586.     if (isdigit(c)) return(DIGIT);
  587.     else return(c);
  588. }
  589.  
  590. pbstr(in)
  591. char *in;
  592. {
  593.     int i;
  594.  
  595.     for (i = strlen(in) - 1; i >= 0; i--)
  596.         putbak(in[i]);
  597. }
  598.  
  599. putbak(c)
  600. char c;
  601. {
  602.     if (bp++ >= CHARBUFSIZE)
  603.         perr("too many chars pushed back\n");
  604.     buf[bp] = c;
  605. }
  606.  
  607. ngetc()
  608. {
  609.     char c;
  610.  
  611.     if (bp < 0) {
  612.         bp = 0;
  613.         while ((buf[bp] = c = agetc()) == '\r')
  614.             ;
  615.         }
  616.     else
  617.         c = buf[bp];
  618.     if (c != CPMEOF)
  619.         bp--;
  620.     return (c);
  621. }
  622.  
  623. agetc()
  624. {
  625.     int c;
  626.  
  627.     if (incflg == YES) {
  628.         if ((c = getc(incbuf)) != CPMEOF)
  629.             return(c);
  630.         else
  631.             incflg = NO;
  632.         }
  633.     return (getc(inbuf));
  634. }
  635.  
  636.  
  637.  
  638.  == YES) {
  639.         if ((c = getc(incbuf)) != CPMEOF)
  640.             return(c);
  641.         else
  642.             incflg